import socket
import tkinter
import tkinter.messagebox
import threading
import json
import tkinter.filedialog
from tkinter.scrolledtext import ScrolledText
import base64


IP = '127.0.0.1'
PORT = '8080'
user = 'A'
listbox1 = ''  # 用于显示在线用户的列表框
show = 1  # 用于判断是开还是关闭列表框
users = []  # 在线用户列表
chat = '------Group chat-------'  # 聊天对象

# 登陆窗口
root0 = tkinter.Tk()
# 设置窗口属性
root0.geometry("300x300")
root0.title('用户登陆窗口')
root0.resizable(0, 0)
# 添加背景标签
one = tkinter.Label(root0, width=300, height=300, bg="LightBlue")
one.pack()
# 创建IP地址和用户名的变量
IP0 = tkinter.StringVar()
IP0.set('')
USER = tkinter.StringVar()
USER.set('')
# 添加IP地址的标签和输入框
labelIP = tkinter.Label(root0, text='IP地址', bg="LightBlue")
labelIP.place(x=20, y=40, width=120, height=40)
entryIP = tkinter.Entry(root0, width=60, textvariable=IP0)
entryIP.place(x=120, y=45, width=120, height=30)
# 添加用户名的标签和输入框
labelUSER = tkinter.Label(root0, text='用户名', bg="LightBlue")
labelUSER.place(x=20, y=120, width=120, height=40)
entryUSER = tkinter.Entry(root0, width=60, textvariable=USER)
entryUSER.place(x=120, y=125, width=120, height=30)


# 登陆
def Login():
    global IP, PORT, user
    IP, PORT = entryIP.get().split(':') # 从`entryIP`中获取用户输入的字符串，并使用`:`作为分隔符将其分割成两部分。
    user = entryUSER.get()
    # 检查用户名是否为空。
    # 如果为空，则显示一个警告消息框；否则，销毁`root0`窗口（即关闭登录窗口）。
    if not user:
        tkinter.messagebox.showwarning('warning', message='用户名为空!')
    else:
        root0.destroy()
# 创建登录按钮
loginButton = tkinter.Button(root0, text="登录", command=Login, bg="Yellow")
loginButton.place(x=135, y=200, width=40, height=25)


# 处理窗口关闭事件
def Exit():
    response = tkinter.messagebox.askyesno("退出", "你确定要退出程序吗？")
    if response:
        root0.destroy() # 销毁主窗口root0
        exit() # 退出Python程序
root0.protocol("WM_DELETE_WINDOW", Exit) # 绑定窗口关闭协议
root0.mainloop() # 启动主事件循环

# 创建Socket对象并连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect方法连接到指定的服务器地址和端口
# PORT被转换为了整数类型，因为端口号必须是整数
s.connect((IP, int(PORT)))
if user:
    s.send(user.encode())  # 发送用户名
else:
    s.send('用户名不存在'.encode())
    user = IP + ':' + PORT

# 创建聊天窗口
root1 = tkinter.Tk()
root1.geometry("640x480") # 设置聊天窗口的属性
root1.title('Achat')
root1.resizable(0, 0)

# 创建消息界面
listbox = ScrolledText(root1)
listbox.place(x=5, y=0, width=640, height=320)
listbox.tag_config('tag1', foreground='red', background="white")
listbox.insert(tkinter.END, '欢迎进入群聊，大家开始聊天吧!', 'tag1')
# 创建输入框
INPUT = tkinter.StringVar()
INPUT.set('')
entryInput = tkinter.Entry(root1, width=120, textvariable=INPUT)
entryInput.place(x=5, y=320, width=580, height=170)
# 创建在线用户列表
listbox1 = tkinter.Listbox(root1)
listbox1.place(x=510, y=0, width=130, height=320)

def send():
    # 将字符串转换为字节串进行Base64编码并发送
    message = entryInput.get() + '~' + user + '~' + chat
    base64_message = base64.b64encode(message.encode())
    s.send(base64_message) # 通过已建立的socket（s）发送Base64编码后的消息
    entryInput.delete(0, 'end') # 清空输入框
# 创建发送按钮
sendButton = tkinter.Button(root1, text="\n发\n\n\n送", anchor='n', command=send, font=('Helvetica', 18),
                            bg='LightBlue')
sendButton.place(x=510, y=320, width=130, height=300)


def receive():
    global users
    while True:
        try: # 从套接字 s 接收最多 1024 字节的数据，并将其解码为字符串
            data = s.recv(1024)
            data = data.decode()
            print(data)
            #处理在线用户列表
            try: # 更新列表框
                users = json.loads(data)
                listbox1.delete(0, tkinter.END)
                listbox1.insert(tkinter.END, "当前在线用户")
                listbox1.insert(tkinter.END, "------Group chat-------")
                for x in range(len(users)):
                    listbox1.insert(tkinter.END, users[x])
                users.append('------Group chat-------')
            except: # 处理聊天消息
                data = data.split('~')
                message = data[0]
                userName = data[1]
                chatwith = data[2]
                message = '\n' + message
                if chatwith == '------Group chat-------':  # 群聊
                    if userName == user:
                        listbox.insert(tkinter.END, message)
                    else:
                        listbox.insert(tkinter.END, message)
                elif userName == user or chatwith == user:  # 私聊
                    if userName == user:
                        listbox.tag_config('tag2', foreground='red')
                        listbox.insert(tkinter.END, message, 'tag2')
                    else:
                        listbox.tag_config('tag3', foreground='green')
                        listbox.insert(tkinter.END, message, 'tag3')
                listbox.see(tkinter.END) # 列表框的滚动条滚动到最新插入的消息处
        except:
            pass


r = threading.Thread(target=receive) # 创建线程 启动这个线程时将执行receive函数
# 将线程r设置为守护线程。这意味着如果您的主程序完成了它的工作并准备退出，那么守护线程会被强制结束
r.setDaemon(True)
r.start()  # 启动线程


def Exit():
    response = tkinter.messagebox.askyesno("退出", "你确定要退出程序吗？")
    if response:
        tkinter.messagebox.showinfo("提示", "退出成功！")
        root1.destroy()
        s.close()
        exit()

root1.protocol("WM_DELETE_WINDOW", Exit)
root1.mainloop()